package tpoo.server.model.users;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;

import tpoo.common.dto.model.ObjectID;
import tpoo.common.dto.model.users.UserDTO;
import tpoo.common.dto.model.users.status.Presence;
import tpoo.common.utils.passiveOperations.AfterLoginOperation;
import tpoo.common.utils.passiveOperations.LogoutOperation;
import tpoo.common.utils.passiveOperations.MessageReceivedOperation;
import tpoo.common.utils.passiveOperations.NewContact;
import tpoo.common.utils.passiveOperations.PassiveOperation;
import tpoo.common.utils.passiveOperations.PresenceChangedOperation;
import tpoo.common.utils.passiveOperations.UpdateContactsOperation;

public class User extends DomainObject{

	
	private static final long serialVersionUID = 1L;
	
	private Date sessionStarted;
	private String username;
	
	public User(String username, Long id) {
		super(id);
		setSessionStarted(new Date());
		setUsername(username);
	}
	
	public Date sessionStarted() {
		return this.getSessionStarted();
	}
	
	public void setSessionStarted(Date sessionStarted) {
		this.sessionStarted = sessionStarted;
	}
	
	public Date getSessionStarted() {		
		return sessionStarted;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getUsername() {
		return username;
	}

	@Override
	public String toString() {
		return this.getUsername();
	}

	private Boolean isContact( User aUser ){
		return this.getContacts().contains(aUser);
	}
	
	public void sendMessage(User t, String message) {
		if (this.isContact(t))
			t.receive(message, this);
		else
			throw new RuntimeException(t +" is not contact of " + this);
	}

	@Deprecated
	private List<String> messages= new ArrayList<String>();
	private List<PassiveOperation> actions = new ArrayList<PassiveOperation>();
	private void receive(String message, User from ) {
		this.messages.add(message);
		PassiveOperation poperation = new MessageReceivedOperation(message, from.getId());
		this.actions.add( poperation );
		this.setChanged();
		this.notifyObservers(poperation);
	}

	
	@Override
	public ObjectID getId() {
		return new ObjectID(this.getUsername());
	}
	
	private Presence presence = Presence.ONLINE;
	
	public void setPresence(Presence presence) {
		this.presence=presence; 
		this.setChanged();
		this.notifyObservers(new PresenceChangedOperation(presence));
	}
	
	public Presence getPresence(){
		return this.presence;
	}
	
	private List<User> contacts = new Vector<User>();
	public void addContact(User anotherUser) {
		if (contacts.contains(anotherUser))
			return ;
		contacts.add(anotherUser);
		this.setChanged();
		this.notifyObservers(new NewContact(new UserDTO(anotherUser.getUsername(), anotherUser.getPresence())));
		
		//se agregan mutuamente... ¿para testing solamente?
		anotherUser.addContact(this);
		
	}

	public List<User> getContacts() {
		return contacts;
	}

	public void succesfullyLoggedIn() {
		setChanged();
		notifyObservers(new AfterLoginOperation(new UserDTO(getUsername(),this.getPresence())));
	}
	
	public void logout(){
		this.setPresence(Presence.OFFLINE);
		
		//Actualizo los contactos de los mis contactos ("donde estoy yo")
		for (User contact: this.getContacts()){
			contact.updateContacts();
		}
		
		setChanged();
		notifyObservers(new LogoutOperation());
	}

	public void delContact(User contact){
		this.getContacts().remove(contact);	
	}
	
	private void updateContacts(){
		this.setChanged();
		this.notifyObservers(new UpdateContactsOperation());
	}
	
	
}
